package com.xinchili.autoddl.autoClass.processor;


import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.xinchili.autoddl.autoClass.properties.EntityScanProperties;
import com.xinchili.autoddl.autoClass.resolver.strategy.*;
import com.xinchili.autoddl.autoClass.util.JdbcUtils;
import com.xinchili.autoddl.autoClass.util.CommontUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;

import javax.annotation.PostConstruct;
import java.lang.reflect.Field;

import java.util.List;
import java.util.Map;
import java.util.Set;

public class EntityProcessor {

    private static final Logger log = LoggerFactory.getLogger(EntityProcessor.class);

    private final ColumnNameLogic columnNameLogic;
    private final ColumnTypeLogic columnTypeLogic;
    private final TableCommentLogic tableCommentLogic;
    private final ColumnCommentLogic columnCommentLogic;
    private final EntityScanProperties entityScanProperties;
    private final ScanLogic scanLogic;

    @Autowired
    private JdbcTemplate jdbcTemplate;

    public EntityProcessor(
            ColumnNameLogic columnNameLogic,
            ColumnTypeLogic columnTypeLogic,
            TableCommentLogic tableCommentLogic,
            ColumnCommentLogic columnCommentLogic,
            EntityScanProperties entityScanProperties,
            ScanLogic scanLogic
    ) {
        this.columnNameLogic = columnNameLogic;
        this.columnTypeLogic = columnTypeLogic;
        this.tableCommentLogic = tableCommentLogic;
        this.entityScanProperties = entityScanProperties;
        this.columnCommentLogic = columnCommentLogic;
        this.scanLogic = scanLogic;
    }

    /**
     * 扫描所有entity和domain包下的实体类
     * 生成ddl语句来建表
     */
    @PostConstruct
    public void init() {
        List<String> packages = entityScanProperties.getTablePackage();
        Integer scanLevel = entityScanProperties.getScanLevel();
        log.info("scanLevel: " + scanLevel);
        log.info("packages: " + packages);
        String projectRoot = System.getProperty("user.dir");
        log.info("projectRoot:{}", projectRoot);
        // 示例：扫描包路径下所有带有 @TableName 的类
        Set<Class<?>> entityClasses = null;
        try {
            entityClasses = scanLogic.scanLogic(entityScanProperties);
        } catch (Exception e) {
            log.error("发现异常CommontUtil.scanClassesWithAnnotation", e);
            throw new RuntimeException(e);
        }
        log.info("扫描到的实体类数量: " + entityClasses.size());
        for (Class<?> clazz : entityClasses) {
            processEntityClass(clazz);
        }
    }

    /**
     * 处理class对象
     *
     * @param clazz
     */

    public void processEntityClass(Class<?> clazz) {

        String tableName;

        tableName = clazz.getSimpleName();
        //获取@TableName注解的值
        TableName anno = clazz.getAnnotation(TableName.class);
        log.info("处理类" + clazz.getTypeName());
        //如果存在，则获取注解的值作为表名
        if (anno != null) {
            tableName = anno.value();
        }
        if (!JdbcUtils.tableExists(jdbcTemplate, tableName)) {
            createTable(tableName, clazz);
        } else {
            alterTable(tableName, clazz);
        }
    }

    private void createTable(String tableName, Class<?> clazz) {
        StringBuilder sqlBuilder = new StringBuilder();
        sqlBuilder.append("CREATE TABLE ").append(tableName).append(" (");

        List<Field> fields = CommontUtil.getAllFields(clazz);
        for (Field field : fields) {
            String columnName = columnNameLogic.resolveColumnName(field);
            if (columnName == null) continue;

            String columnType = columnTypeLogic.resolveColumnType(field);
            String columnComment = columnCommentLogic.resolveColumnComment(field);

            sqlBuilder.append(columnName).append(" ").append(columnType);

            if (field.isAnnotationPresent(TableId.class)) {
                // 判断是否是主键（可扩展）
                sqlBuilder.append(" PRIMARY KEY");
            }

            if (!columnComment.isEmpty()) {
                sqlBuilder.append(" COMMENT '").append(columnComment).append("'");
            }

            sqlBuilder.append(", ");
        }

        if (sqlBuilder.toString().endsWith(", ")) {
            sqlBuilder.setLength(sqlBuilder.length() - 2); // 去掉最后的逗号空格
        }

        String tableComment = tableCommentLogic.resolveTableComment(clazz);
        sqlBuilder.append(") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC");
        if (!tableComment.isEmpty()) {
            sqlBuilder.append(" COMMENT='").append(tableComment).append("'");
        }
        sqlBuilder.append(";");

        jdbcTemplate.execute(sqlBuilder.toString());
        log.info("已创建表: " + tableName + "\nSQL: " + sqlBuilder);
    }


    private void alterTable(String tableName, Class<?> clazz) {
        Set<String> dbColumns = JdbcUtils.getTableColumns(jdbcTemplate, tableName);
        Map<String, String> dbColumnTypes = JdbcUtils.getColumnTypes(jdbcTemplate, tableName);
        Map<String, String> dbColumnComments = JdbcUtils.getColumnComments(jdbcTemplate, tableName);

        List<Field> fields = CommontUtil.getAllFields(clazz);
        for (Field field : fields) {
            String columnName = columnNameLogic.resolveColumnName(field);
            if (columnName == null) continue;

            String expectedType = columnTypeLogic.resolveColumnType(field);
            String expectedComment = columnCommentLogic.resolveColumnComment(field);

            if (!dbColumns.contains(columnName.toLowerCase())) {
                // 新增字段
                String addSql = String.format(
                        "ALTER TABLE %s ADD COLUMN %s %s COMMENT '%s';",
                        tableName, columnName, expectedType, expectedComment
                );
                jdbcTemplate.execute(addSql);
                log.info("new colume: " + columnName + " in " + tableName);
            } else {
                // 字段存在，检查类型和注释
                String actualType = dbColumnTypes.getOrDefault(columnName.toUpperCase(), "");
                String actualComment = dbColumnComments.getOrDefault(columnName.toUpperCase(), "");

                boolean typeMismatch = !expectedType.equalsIgnoreCase(actualType);
                boolean commentMismatch = !expectedComment.equals(actualComment);

                if (typeMismatch || commentMismatch) {
                    String modifySql = String.format(
                            "ALTER TABLE %s MODIFY COLUMN %s %s COMMENT '%s';",
                            tableName, columnName, expectedType, expectedComment
                    );
                    jdbcTemplate.execute(modifySql);
                    log.info("修改字段: " + columnName + " in " + tableName);
                }

            }
        }
    }

}
